package com.fangdd.logtrace.dubbo;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.fangdd.logtrace.BoundsLog;
import com.fangdd.logtrace.TraceId;
import com.fangdd.logtrace.TraceRootGenerator;
import com.fangdd.logtrace.TraceWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Callable;

/**
 * Created by sulong on 16-9-6.
 */
@Activate(group = Constants.PROVIDER)
public class LogTraceDubboProviderFilter implements Filter {
    private static final Logger LOGGER = LoggerFactory.getLogger(LogTraceDubboProviderFilter.class);

    @Override
    public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException {
        String traceIdString = invocation.getAttachment(DubboConstants.TRACEID_NAME);
        if (traceIdString == null || traceIdString.length() == 0) {
            traceIdString = TraceRootGenerator.newUUIDRoot();
        }

        TraceId traceId = new TraceId(traceIdString);
        try {
            return TraceWith.run(traceId, new Callable<Result>() {
                @Override
                public Result call() throws Exception {
                    String interfaceName = LogTraceDubboConsumerFilter.makeInterfaceName(invoker, invocation);
                    final long startTime = System.currentTimeMillis();
                    BoundsLog.calleeIn(LOGGER, interfaceName);
                    try {
                        Result result = invoker.invoke(invocation);
                        BoundsLog.calleeOut(LOGGER, interfaceName, true, System.currentTimeMillis() - startTime);
                        return result;
                    } catch (RpcException rpcException) {
                        if (rpcException.isBiz()) {
                            BoundsLog.calleeOut(LOGGER, interfaceName, true, System.currentTimeMillis() - startTime);
                        } else {
                            BoundsLog.calleeOut(LOGGER, interfaceName, false, System.currentTimeMillis() - startTime);
                        }
                        throw rpcException;
                    } catch (Exception e) {
                        BoundsLog.calleeOut(LOGGER, interfaceName, false, System.currentTimeMillis() - startTime);
                        throw e;
                    }
                }
            });
        } catch (Exception e) {
            throw new RpcException(e);
        }
    }
}
